"""
CREATE: 2018/5/26
AUTHOR:　HEHAHUTU
"""
from app.models.admin.user import User
from app.models.cloud.folder import DiskFile
from app.models.share.shareList import ShareShip
from flask_restful import Resource, reqparse
from app.api import api
from f_lib.principal.auth import auth_token
from werkzeug.datastructures import FileStorage
from f_lib.code import Msg
from flask import g, make_response, request, Response
from settings import UPLOAD_PATH, PUBLIC_UPLOAD_PATH
import os
from f_lib.celerys.backup_file import back_up_task
import urllib.parse
from f_lib.principal.safety import safety_strategy
from f_lib.tool.img_resize import thumb_image
from f_lib.hash import hash_md5
import chardet


class CreateFile(Resource):
    folder_parse = reqparse.RequestParser()
    # folder_parse.add_argument('event', required=True, type=str)
    folder_parse.add_argument('file', required=True, type=FileStorage, location='files')
    folder_parse.add_argument('group_id', required=True, type=int, location=['form', 'values'])
    folder_parse.add_argument('folder_path', required=True, type=str, location=['form', 'values'])
    folder_parse.add_argument('is_topic', type=int, location=['form', 'values'])

    @auth_token()
    def post(self):
        user_id = g.user.id
        arg = self.folder_parse.parse_args()
        arg['user_id'] = user_id
        file = arg['file']
        arg.pop('file')
        file_data = file.read()
        file_hash = hash_md5(file_data)

        file_size = len(file_data) / 1024
        check_size = True if g.user.max_size > (g.user.use_size + file_size) else False
        if check_size:
            arg['file_size'] = file_size
            arg['name'] = file.filename
            file_obj = DiskFile(**arg)
            file_obj.file_name = file_hash+os.path.splitext(arg['name'])[-1]
            filename = file_obj.file_name
            check_file_is_exist = DiskFile.query_one(file_name=file_hash)
            # save_path = os.path.join(UPLOAD_PATH, g.user.use_folder)
            path = os.path.join(PUBLIC_UPLOAD_PATH, filename)
            if not check_file_is_exist:

                with open(path, 'wb') as f:
                    f.write(file_data)
                is_thumb = thumb_image(PUBLIC_UPLOAD_PATH, filename, size=(80, 80))
                thumb_image(PUBLIC_UPLOAD_PATH, filename, size=(360, 360))
                if is_thumb:
                    file_obj.is_thumb = 1
            file_obj.save()
            arg['path'] = path
            g.user.update(use_size=g.user.use_size + file_size)
            # back_up_task.apply_async(args=[arg, ], countdown=60 * 5)

            return Msg.success(msg='文件上传成功', filename=file_obj.file_name, is_img=file_obj.is_thumb, )
        else:
            return Msg.failed_dict(1001)


class UpdateFile(Resource):
    parse = reqparse.RequestParser()
    parse.add_argument('name', type=str)
    parse.add_argument('id', type=int)
    parse.add_argument('is_share', type=int)

    @safety_strategy
    @auth_token()
    def post(self):
        arg = self.parse.parse_args()
        file = DiskFile.query_one(id=arg['id'], user_id=g.user.id)
        if file:
            file.update(**arg)
            return Msg.success('ok')
        else:
            return Msg.failed_dict(1002)


# 此处删除为逻辑删除
class DeleteFile(Resource):
    parse = reqparse.RequestParser()
    parse.add_argument('id', type=int, required=True)

    @safety_strategy
    @auth_token()
    def post(self):
        arg = self.parse.parse_args()
        file = DiskFile.query_one(id=arg['id'], user_id=g.user.id)
        if file:
            file.update(id=arg['id'], is_trash=1)
            return Msg.success('ok')
        else:
            return Msg.failed_dict(1002)


class DownloadFile(Resource):
    parse = reqparse.RequestParser()
    parse.add_argument('size', type=str)

    @safety_strategy
    @auth_token()
    def get(self, filename=''):

        if filename:
            file = DiskFile.query_one(file_name=filename)
            if file.user_id == g.user.id or file.is_topic ==1:
                if file:
                    arg = self.parse.parse_args()
                    size = arg.get('size')
                    # save_path = os.path.join(UPLOAD_PATH, g.user.use_folder)
                    path = os.path.join(PUBLIC_UPLOAD_PATH, filename)
                    # print(path)
                    header_range = request.headers.get('Range')
                    start_s = 0
                    if os.path.exists(path):
                        headers_len = os.path.getsize(path)
                        if header_range:
                            show_lens = header_range.replace('bytes=', '')
                            start_s = int(show_lens.split('-')[0])

                        def send_file(start_s, path):
                            with open(path, 'rb') as target_file:
                                if start_s > 0:
                                    target_file.seek(start_s)
                                while True:

                                    chunk = target_file.read(20* 1024 * 1024)  # 每次读取20M
                                    if not chunk:
                                        break
                                    yield chunk

                        # with open(path, 'rb') as f:
                        #     data = f.read()
                        name = urllib.parse.quote(file.name)
                        # 图片缩略图逻辑
                        if size:
                            f, t = os.path.splitext(filename)
                            thumb_filename = f + '_{}'.format(size) + t
                            thumb_path = os.path.join(PUBLIC_UPLOAD_PATH, thumb_filename)
                            if os.path.exists(thumb_path):
                                with open(thumb_path, 'rb') as f:
                                    data = f.read()

                                resp = make_response(data)
                                # print(len(data))

                                resp.headers["Content-Disposition"] = f"attachment; filename*=utf-8''{name}"
                                resp.headers["Content-Type"] = f"application/octet-stream; charset=utf-8"
                                # resp.headers["Content-Range"] = f'bytes {start_b}-{ends}/{all_len}'
                                return resp
                            return Msg.failed_dict(5000)

                        # 流式下载

                        headers = {
                            'Accept-Ranges': 'bytes',
                            "Content-Type": 'application/octet-stream; charset=utf-8',
                            'Content-Disposition': f"attachment; filename*=utf-8''{name}",
                            'Content-Length': headers_len - start_s,
                            "Content-Range": f'bytes {start_s}-{headers_len}/{headers_len}'

                        }
                        return Response(send_file(start_s, path), headers=headers)

                return Msg.failed_dict(5000)
        else:
            return Msg.failed_dict(400)


class ShareImage(Resource):
    @safety_strategy
    def get(self, filename=''):

        if filename:
            file = DiskFile.query_one(file_name=filename)
            if file:
                if file.is_share == 1:
                    user = User.get_by_id(file.user_id)
                    # save_path = os.path.join(UPLOAD_PATH, user.use_folder)
                    path = os.path.join(PUBLIC_UPLOAD_PATH, filename)
                    # print(path)
                    with open(path, 'rb') as f:
                        data = f.read()
                    resp = make_response(data)
                    # print(len(data))
                    name = urllib.parse.quote(file.name)

                    resp.headers["Content-Disposition"] = f"attachment; filename*=utf-8''{name}"
                    resp.headers["Content-Type"] = f"application/octet-stream; charset=utf-8"

                    return resp
                return Msg.failed_dict(5000)
            else:
                return Msg.failed_dict(5000)
        else:
            return Msg.failed_dict(400)


class OpenFile(Resource):
    parse = reqparse.RequestParser()
    parse.add_argument('share_key', type=str)


    @safety_strategy
    @auth_token(True)
    def get(self, filename=''):
        arg = self.parse.parse_args()

        if filename:
            file = DiskFile.query_one(file_name=filename)
            if file:
                share = ShareShip.query_one(**arg)
                is_share = share.type_id == file.id if share else False
                if is_share or g.user.id == file.user_id:
                    user = User.get_by_id(file.user_id)
                    # save_path = os.path.join(UPLOAD_PATH, user.use_folder)
                    path = os.path.join(PUBLIC_UPLOAD_PATH, filename)
                    with open(path, 'rb') as f:
                        data = f.read()
                    encode_result = chardet.detect(data)
                    if encode_result.get('encoding'):
                        encode = 'GBK' if encode_result.get('encoding').startswith('GB') else 'utf8'
                        with open(path, 'r', encoding=encode) as f:
                            data = f.read()
                    resp = make_response(data)
                    # print(len(data))
                    name = urllib.parse.quote(file.name)

                    resp.headers["Content-Disposition"] = f"attachment; filename*=utf-8''{name}"
                    resp.headers["Content-Type"] = f"application/octet-stream; charset=utf-8"

                    return Response(data)
                return Msg.failed_dict(5000)
            else:
                return Msg.failed_dict(5000)
        else:
            return Msg.failed_dict(400)


api.add_resource(CreateFile, '/file/add', endpoint='c_file')
api.add_resource(UpdateFile, '/file/update', endpoint='u_file')
api.add_resource(DeleteFile, '/file/delete', endpoint='d_file')
api.add_resource(DownloadFile, '/file/<string:filename>', endpoint='downloadFile')
api.add_resource(ShareImage, '/file/share/image/<string:filename>', endpoint='img_download')
api.add_resource(OpenFile, '/file/open/<string:filename>', endpoint='open_file')
